/*
  +----------------------------------------------------------------------+
  | PHP Version 7                                                        |
  +----------------------------------------------------------------------+
  | Copyright (c) 1997-2018 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP license,      |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author:                                                              |
  +----------------------------------------------------------------------+
*/

/* $Id$ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_scarecrow.h"
/* If you declare any globals in php_scarecrow.h uncomment this:
ZEND_DECLARE_MODULE_GLOBALS(scarecrow)
*/

/* True global resources - no need for thread safety here */


/* {{{ PHP_INI
 */
/* Remove comments and fill if you need to have entries in php.ini
PHP_INI_BEGIN()
    STD_PHP_INI_ENTRY("scarecrow.global_value",      "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_scarecrow_globals, scarecrow_globals)
    STD_PHP_INI_ENTRY("scarecrow.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_scarecrow_globals, scarecrow_globals)
PHP_INI_END()
*/
/* }}} */

PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("scarecrow.age", "42", PHP_INI_ALL, OnUpdateLong, age, zend_scarecrow_globals, scarecrow_globals)
STD_PHP_INI_ENTRY("scarecrow.name", "pengqingsong", PHP_INI_ALL, OnUpdateString, name, zend_scarecrow_globals, scarecrow_globals)
PHP_INI_END()


/* Remove the following function when you have successfully modified config.m4
   so that your module can be compiled into PHP, it exists only for testing
   purposes. */
/*
输出zavl变量 s
*/
void printZval(zval z)
{
	switch (Z_TYPE(z))
	{
	case IS_NULL:
		php_printf("NULL");
		break;
	case IS_LONG:
		php_printf("%f", Z_LVAL(z));
		break;
	case IS_DOUBLE:
		php_printf("%f",Z_DVAL(z));
		break;
	case IS_STRING:
		php_printf("str:%s len:%d", Z_STRVAL(z), Z_STRLEN(z));
		break;
	case IS_ARRAY:
		php_printf("Array");
		break;
	case IS_OBJECT:
		php_printf("Object");
		break;
	default:
		php_printf("Error type!");
		break;
	}
}

/*
打印日志信息
*/
#ifdef SCARECROW_DEBUG
static inline void trace(const char *file, int line, const char* function, const char *fmt, ...) {
	fprintf(stderr, "%s(%s:%d) - ", function, file, line);
	va_list args;
	va_start(args, fmt);
	vfprintf(stderr, fmt, args);
	fprintf(stderr, "\n");
	va_end(args);
}
#else
static inline void trace(const char *file, int line, const char* function, const char *fmt, ...) {
	
}
#endif
/* 自定义函数参数变量列表定义区s */
/* 转换字符串为小写的参数列表s */
ZEND_BEGIN_ARG_INFO_EX(scarecrow_strtolower_args, 0, 0, 1)
ZEND_ARG_INFO(0, str)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(scarecrow_addpwdfile_args, 0, 0, 1)
ZEND_ARG_INFO(0, str)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(scarecrow_runpwdfile_args, 0, 0, 1)
ZEND_ARG_INFO(0, str)
ZEND_END_ARG_INFO()

/* 自定义函数实现区s */
PHP_FUNCTION(confirm_scarecrow_compiled) {
	//zval b;
	//ZVAL_BOOL(&b, 1);
	//返回值的真实表达是将对象赋值到*return_value 上面，他是一个指针，外部将这个指针的值传递出去当成函数的返回值，也有宏的快捷方式来返回 ，但是解析后仍然是*return_value=xxx的形式，所以用那种看你自己(所有的宏定义返回列表)
	/*
	#define RETURN_BOOL(b) 					{ RETVAL_BOOL(b); return; }
	#define RETURN_NULL() 					{ RETVAL_NULL(); return;}
	#define RETURN_LONG(l) 					{ RETVAL_LONG(l); return; }
	#define RETURN_DOUBLE(d) 				{ RETVAL_DOUBLE(d); return; }
	#define RETURN_STR(s) 					{ RETVAL_STR(s); return; }
	#define RETURN_INTERNED_STR(s)			{ RETVAL_INTERNED_STR(s); return; }
	#define RETURN_NEW_STR(s)				{ RETVAL_NEW_STR(s); return; }
	#define RETURN_STR_COPY(s)				{ RETVAL_STR_COPY(s); return; }
	#define RETURN_STRING(s) 				{ RETVAL_STRING(s); return; }
	#define RETURN_STRINGL(s, l) 			{ RETVAL_STRINGL(s, l); return; }
	#define RETURN_EMPTY_STRING() 			{ RETVAL_EMPTY_STRING(); return; }
	#define RETURN_RES(r) 					{ RETVAL_RES(r); return; }
	#define RETURN_ARR(r) 					{ RETVAL_ARR(r); return; }
	#define RETURN_EMPTY_ARRAY()			{ RETVAL_EMPTY_ARRAY(); return; }
	#define RETURN_OBJ(r) 					{ RETVAL_OBJ(r); return; }
	#define RETURN_ZVAL(zv, copy, dtor)		{ RETVAL_ZVAL(zv, copy, dtor); return; }
	#define RETURN_FALSE  					{ RETVAL_FALSE; return; }
	#define RETURN_TRUE						{ RETVAL_TRUE; return; }
	*/
	//*return_value = b;
	//RETURN_BOOL(1);
	
	RETURN_BOOL(1);
	return ;
}

void strtolower(char *str, size_t strLen) {
	size_t i = 0;
	while (i < strLen) {
		if (*str < 65 || *str > 90) {
			str++;
			continue;
		}
		*str = *str + 32;
		str++;
		i++;
	}
}

PHP_FUNCTION(scarecrow_test) {
	/********************调用一个类的静态函数方式s************/
	zend_string *myext_classname = zend_string_init("scarecrow", sizeof("scarecrow") - 1, 0);
	//查找类
	zend_class_entry *myext_handle = zend_lookup_class(myext_classname);
	zend_string_release(myext_classname);

	//准备调用静态函数相关参数s
	zval retval;
	zend_fcall_info fci = {
			.size=sizeof(zend_fcall_info),
			.retval=&retval,
			.params=NULL,
			.object=NULL,
			.no_separation=1,
			.param_count=0,
	};
	ZVAL_UNDEF(&fci.function_name);

	//获取静态函数句柄s 注意这里查找的函数名字全部都要转为小写，否则找不到，因为function_table中存储的都是小写，这也是为什么PHP调用函数时不区分大小写的原因s
	zval *print_author_func = zend_hash_str_find(&(myext_handle->function_table), "getextname", sizeof("getextname") - 1);


	zend_fcall_info_cache fcic = {
			.function_handler=print_author_func->value.func,
			.calling_scope=myext_handle,
			.called_scope=NULL,
			.object=NULL,
	};
	//调用函数
	zend_call_function(&fci, &fcic);
	RETURN_ZVAL(&retval, 1, 1);
}

PHP_FUNCTION(scarecrow_resource) {
	char *string = strdup("i am a scarecrow string resource");
	zend_resource *res = zend_register_resource(string, scarecrow_string_resource_id);

	// wrappped with zval, refcount=2
	zval res_zval;
	ZVAL_RES(&res_zval, res);
	zval_addref_p(&res_zval);
	assert(GC_REFCOUNT(res) == 2);

	// release resource directly, left refcount=1
	zend_list_delete(res);
	assert(GC_REFCOUNT(res) == 1);

	// validate and get resource ptr
	char *s = zend_fetch_resource_ex(&res_zval, SCARECROW_STRING_RESOURCE_DTOR, scarecrow_string_resource_id);
	assert(strcmp(s, "i am a scarecrow string resource") == 0);

	RETURN_STRING(res->ptr);
	// release resource through zval, left refcount=0, zend_list_free is called
	zval_ptr_dtor(&res_zval);
}

/* include文件 */
PHP_FUNCTION(scarecrow_include) {
	int num_args = ZEND_CALL_NUM_ARGS(execute_data);
	zval *args = ZEND_CALL_ARG(execute_data, 1);

	// relative path to absolute full path
	char realpath[MAXPATHLEN];
	if (!virtual_realpath(Z_STRVAL(args[0]), realpath)) {
		ZVAL_BOOL(return_value, 0);
		return;
	}

	TRACE("realpath=%s", realpath);

	zend_string *filename = zend_string_init(realpath, strlen(realpath), 0);

	// already loaded before
	zval *existed = zend_hash_find(&EG(included_files), filename);
	if (existed) {
		zend_string_release(filename);
		ZVAL_BOOL(return_value, 0);
		return;
	}

	// not opened file handle
	zend_file_handle file_handle = {
			.filename=filename->val,
			.free_filename=0,
			.type=ZEND_HANDLE_FILENAME,
			.opened_path=NULL,
			.handle={.fp=NULL},
	};

	// compile file into opcode 使用文件编译到内核s
	zend_op_array *op_array = zend_compile_file(&file_handle, ZEND_INCLUDE);
	assert(op_array);

	//使用字符串编译到内核 当此段代码执行后再php文件中调用aa()是可以成功的
	/*
	zend_string *codeing = zend_string_init("function aa(){return 'LOVE';}", sizeof("function aa(){return 'LOVE';}") - 1, 0);
	zval code;
	ZVAL_STR(&code, codeing);
	zend_compile_string(&code, "PQS.php");
	*/



	// mark file is included
	zval empty_zv;
	ZVAL_NULL(&empty_zv);
	assert(zend_hash_add_new(&EG(included_files), filename, &empty_zv)); // 1 ref added inner
	zend_string_release(filename);

	// close file handle
	zend_destroy_file_handle(&file_handle);

	// execute opcode
	zval result;
	ZVAL_UNDEF(&result);
	zend_execute(op_array, &result);

	// free opcode
	destroy_op_array(op_array);
	efree(op_array);

	// array included from php file
	assert(Z_TYPE(result) == IS_ARRAY);
	*return_value = result;
}


//读取整个文件s
char* readFilePath(char *filePath) {
	FILE * pFile;
	long lSize;
	char * buffer;
	size_t result;

	/* 若要一个byte不漏地读入整个文件，只能采用二进制方式打开s */
	pFile = fopen(filePath, "rb");
	if (pFile == NULL)
	{
		fputs("File error", stderr);
		exit(1);
	}

	/* 获取文件大小 */
	fseek(pFile, 0, SEEK_END);
	lSize = ftell(pFile);
	rewind(pFile);

	/* 分配内存存储整个文件 */
	buffer = (char*)malloc(lSize + 1);
	if (buffer == NULL)
	{
		fputs("Memory error", stderr);
		exit(2);
	}

	/* 将文件拷贝到buffer中 */
	result = fread(buffer, 1, lSize, pFile);
	if (result != lSize)
	{
		fputs("Reading error", stderr);
		exit(3);
	}

	buffer[lSize] = '\0';
	fclose(pFile);
	return buffer;
}

//给文件内容加密s
char* addPwdFileContent(char *fileContent) {
	char tempStr[6];
	strncpy(tempStr, fileContent, 5);
	tempStr[5] = '\0';
	if (strcmp(tempStr, "<?php") != 0) {
		printf("this file not is php file!");
		exit(1);
	}

	size_t lSize = 0, nSize = 0;
	char *tempStrAdd = fileContent;
	while (*tempStrAdd != '\0')
	{
		lSize++;
		tempStrAdd++;
	}

	nSize = lSize - 5;
	char *newStr = (char *)malloc(nSize + 1);
	strcpy(newStr, fileContent + 5);
	tempStrAdd = newStr;
	while (*tempStrAdd != '\0')
	{
		*tempStrAdd = *tempStrAdd + 1;
		tempStrAdd++;
	}

	return newStr;
}

//给文件内容解密s
char* unAddPwdFileContent(char *fileContent) {
	char *tempStr = fileContent;
	while (*tempStr != '\0')
	{
		*tempStr = *tempStr - 1;
		tempStr++;
	}
	return fileContent;
}

//写入文件s
void writeFile(char *fileName, char* fileContent) {
	FILE *f;
	size_t lSize = 0, nSize = 0;
	char *tempStrAdd = fileContent;
	while (*tempStrAdd != '\0')
	{
		lSize++;
		tempStrAdd++;
	}
	f = fopen(fileName, "wb");
	fwrite(fileContent, 1, lSize, f);
	fclose(f);
}

/* 给文件加密s */
ZEND_METHOD(scarecrow, addPwdFile) {
	char *str = NULL, *tempStr = NULL;
	size_t strLen;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &strLen) == FAILURE) {
		return;
	}

	zend_string *filename = zend_string_init(str, strlen(str) - 1, 0);

	// already loaded before
	zval *existed = zend_hash_find(&EG(included_files), filename);
	if (existed) {
		zend_string_release(filename);
		ZVAL_BOOL(return_value, 0);
		return;
	}

	char *fileContent = readFilePath(str);
	char *pwdContent = addPwdFileContent(fileContent);
	writeFile(str, pwdContent);
	RETURN_BOOL(1);
}

/* 运行加密文件s */
ZEND_METHOD(scarecrow, runPwdFile) {
	char *filename = NULL, *tempStr = NULL;
	size_t filenameLen;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filenameLen) == FAILURE) {
		return;
	}

	char *fileContent = readFilePath(filename);
	char *pwdContent = unAddPwdFileContent(fileContent);

	size_t lSize = 0;
	char *tempStrAdd = pwdContent;
	while (*tempStrAdd != '\0')
	{
		lSize++;
		tempStrAdd++;
	}

	zend_string *codeing = zend_string_init(pwdContent, lSize, 0);
	zval code;
	ZVAL_STR(&code, codeing);
	zend_op_array *op_array = zend_compile_string(&code, filename);

	// mark file is included
	zend_string *testFile = zend_string_init(filename, filenameLen, 0);
	zval empty_zv;
	ZVAL_NULL(&empty_zv);
	zend_hash_add_new(&EG(included_files), testFile, &empty_zv);
	zend_string_release(testFile);

	// execute opcode
	zval result;
	ZVAL_UNDEF(&result);
	zend_execute(op_array, &result);

	// free opcode
	destroy_op_array(op_array);
	efree(op_array);
	*return_value = result;
}

//构造函数s
ZEND_METHOD(scarecrow, __construct) {
	//获取当前对象的zval地址
	zval *this = &(execute_data->This);
	//获取当前对象的类结构描述
	zend_class_entry *class_handle = this->value.obj->ce;
	
	zend_string *ver_prop_name = zend_string_init("versions", sizeof("versions") - 1, 0);
	zend_string *new_ver_prop = zend_string_init("2.0.1", sizeof("2.0.1") - 1, 0);
	zval ver_zval;
	ZVAL_STR(&ver_zval, new_ver_prop);
	//更新当前类的属性值
	zend_update_property_ex(class_handle, this, ver_prop_name, &ver_zval);
	//释放zend_string变量空间
	zend_string_release(ver_prop_name);
	//释放变量ver_zval的空间
	zval_ptr_dtor(&ver_zval);
}

ZEND_METHOD(scarecrow, author) {
	RETURN_STRING("I AM SCARECROW");
}

//版本函数s
ZEND_METHOD(scarecrow, version) {
	// same as $this
	zval *this = &(execute_data->This);

	// class handle of this object
	zend_class_entry *class_handle = this->value.obj->ce;
	zval *ver_prop = zend_read_property(class_handle, this, "versions", sizeof("versions") - 1, 0, NULL);
	if (Z_TYPE_P(ver_prop) == IS_STRING) {
		zend_string *dup = zend_string_init(ver_prop->value.str->val, ver_prop->value.str->len, 0);
		RETURN_STR(dup);
	}
	else {
		RETURN_BOOL(0);
	}
}


//将字符串转为小写  （采用自己实现转换函数实现）s
ZEND_METHOD(scarecrow, strtolower) {
	char *str=NULL,*tempStr = NULL;
	size_t strLen;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &strLen) == FAILURE) {
		return;
	}

	tempStr = (char *)malloc(strLen);
	memcpy(tempStr, str, strLen);
	strtolower(tempStr, strLen);
	zend_string *relStr = zend_string_init(tempStr, strLen, 0);
	free(tempStr);
	RETURN_STR(relStr);
}

//将字符串转为大写  （采用调用PHP的全局函数来实现）s
ZEND_METHOD(scarecrow, strtoupper) {
	int num_args = ZEND_CALL_NUM_ARGS(execute_data);
	zval *args = ZEND_CALL_ARG(execute_data, 1);

	//调用全局函数
	zend_string *func_name = zend_string_init("strtoupper", sizeof("strtoupper") - 1, 0);
	zval func_name_zval;
	ZVAL_STR(&func_name_zval, func_name);

	//调用PHP内置方法的方法 其中这个call_user_function方法可以调用当前类的方法以及继承的方法
	call_user_function(&EG(function_table), NULL, &func_name_zval, return_value, 1, &args[0]);
	zval_ptr_dtor(&func_name_zval);
}


ZEND_METHOD(scarecrow, test) {
	/***********************调用PHP代码中生成注册的类及其方法（注意不管是扩展、内核、PHP代码编写的方法和类都会全局注册到Zend引擎中，所以在扩展中可以使用zend_lookup_class查找到对应的类以及使用object_init_ex进行实例化后就可以使用call_user_function方法调用对象中的函数了）s****************************/
	zend_string *myext_classname = zend_string_init("TestPqs", sizeof("TestPqs") - 1, 0);
	/*查找Zend引擎中的类描述s*/

	zend_class_entry *myext_handle = zend_lookup_class(myext_classname);
	zend_string_release(myext_classname);

	/*初始化对象 注意此对象不会自动调用构造函数s*/
	zval myext_obj;
	object_init_ex(&myext_obj, myext_handle);

	/*使用call_user_function调用对象的构造函数s*/
	zval ctor_name;
	zval ctor_retval;
	ZVAL_STR(&ctor_name, zend_string_init("__construct", sizeof("__construct") - 1, 0));
	call_user_function(&EG(function_table), &myext_obj, &ctor_name, &ctor_retval, 0, NULL);
	zval_ptr_dtor(&ctor_name);

	/*使用call_user_function对象的任意函数s*/
	zval func_name;
	ZVAL_STR(&func_name, zend_string_init("getName", sizeof("getName") - 1, 0));
	zval retval;
	call_user_function(&EG(function_table), &myext_obj, &func_name, &retval, 0, NULL);
	zval_ptr_dtor(&func_name);

	/*将结果返回s*/
	//*return_value = retval;
	//zval_ptr_dtor(&retval);
	RETURN_ZVAL(&retval, 1, 1);
}

ZEND_METHOD(scarecrow, getExtName) {
	RETURN_STRING("SCARCROW EXT");
}


ZEND_METHOD(scarecrow, test_arr) {
	//初始化数组s
	zval arr_zval;
	assert(array_init(&arr_zval) == SUCCESS);

	// add k-v 添加K-V数据
	add_assoc_long(&arr_zval, "date", 20170811);
	assert(zend_hash_str_exists(arr_zval.value.arr, "date", sizeof("date") - 1));

	// add v 添加V数据，引擎自动处理下标
	assert(add_next_index_string(&arr_zval, "hahaha") == SUCCESS);

	// arr count
	assert(zend_hash_num_elements(arr_zval.value.arr) == 2);

	// traversal arr 遍历数组
	zend_array *arr = arr_zval.value.arr;
	int i;
	for (i = 0; i < arr->nNumUsed; ++i) {
		zval *val = &(arr->arData[i].val);
		// handle indirect zval
		if (Z_TYPE_P(val) == IS_INDIRECT) {
			val = Z_INDIRECT_P(val);
		}
		// empty slots
		if (Z_TYPE_P(val) == IS_UNDEF) {
			continue;
		}

		if (arr->arData[i].key) { // must be array["date"]
			TRACE("arr['%.*s']=%ld", arr->arData[i].key->len, arr->arData[i].key->val, val->value.lval);
		}
		else { // must be array[0]
			TRACE("arr[%ld]=%.*s", arr->arData[i].h, val->value.str->len, val->value.str->val);
		}
	}

	// find key
	zval *zv_in_arr = zend_hash_str_find_ind(arr_zval.value.arr, "date", sizeof("date") - 1);
	assert(zv_in_arr->value.lval == 20170811);

	// del string key
	assert(zend_hash_str_del(arr_zval.value.arr, "date", sizeof("date") - 1) == SUCCESS);

	// del index key
	assert(zend_hash_index_del(arr_zval.value.arr, 0) == SUCCESS);

	// release arr
	zval_ptr_dtor(&arr_zval);
}

/*在当前类中调用父类中的方法s*/
ZEND_METHOD(scarecrow_child, version) {
	zval *this = &(execute_data->This);

	// call parent's version()
	zval retval;
	zend_fcall_info fci = {
			.size=sizeof(zend_fcall_info),
			.retval=&retval,
			.params=NULL,
			.object=this->value.obj,
			.no_separation=1,
			.param_count=0,
	};
	ZVAL_UNDEF(&fci.function_name);

	// find parent's version method
	zval *parent_version_func = zend_hash_str_find(&(this->value.obj->ce->parent->function_table), "version", sizeof("version") - 1);

	/*function_handler:函数句柄
	calling_scope:调用的函数所属类描述
	called_scope：调用函数的类描述
	object:调用的对象s*/
	zend_fcall_info_cache fcic = {
			.function_handler=parent_version_func->value.func,
			.calling_scope=this->value.obj->ce->parent,
			.called_scope=this->value.obj->ce,
			.object=this->value.obj,
	};

	zend_call_function(&fci, &fcic);

	int len = retval.value.str->len + sizeof(".child") - 1;
	char *child_version = emalloc(len);
	memcpy(child_version, retval.value.str->val, retval.value.str->len);
	memcpy(child_version + retval.value.str->len, ".child", sizeof(".child") - 1);

	ZVAL_STR(return_value, zend_string_init(child_version, len, 0));
	efree(child_version);
	zval_ptr_dtor(&retval);
}

/** 在当前类中调用当前类的方法或继承的方法或全局方法s */
ZEND_METHOD(scarecrow_child, author_1) {
	//RETURN_STRING("scarecrow_child version 1.0.0");
	//调用全局函数s
	/*获取当前类对象 这里的this=php中的$this*/
	zval *this = &(execute_data->This);
	zend_string *func_name = zend_string_init("author", sizeof("author") - 1, 0);
	zval func_name_zval;
	ZVAL_STR(&func_name_zval, func_name);
	/*调用PHP某个类内置方法的方法(同时也可以调用当前类的方法及继承的方法) call_user_function的第二个参数是传入实例化后的对象而不是类描述s*/
	call_user_function(&EG(function_table), this, &func_name_zval, return_value, 0, NULL);
	zval_ptr_dtor(&func_name_zval);
}

/* Every user-visible function in PHP should document itself in the source */
/* {{{ proto string confirm_scarecrow_compiled(string arg)
   Return a string to confirm that the module is compiled in */


/* }}} */
/* The previous line is meant for vim and emacs, so it can correctly fold and
   unfold functions in source code. See the corresponding marks just before
   function definition, where the functions purpose is also documented. Please
   follow this convention for the convenience of others editing your code.
*/



/* {{{ php_scarecrow_init_globals
 */
/* Uncomment this function if you have INI entries
static void php_scarecrow_init_globals(zend_scarecrow_globals *scarecrow_globals)
{
	scarecrow_globals->global_value = 0;
	scarecrow_globals->global_string = NULL;
}
*/
/* }}} */


/* {{{ PHP_MSHUTDOWN_FUNCTION
此函数为生命周期函数，当模块被卸载的时候调用
*/
PHP_MSHUTDOWN_FUNCTION(scarecrow)
{
	TRACE("this is mshutdown function!");
	/* uncomment this line if you have INI entries
	UNREGISTER_INI_ENTRIES();
	*/
	//销毁配置文件的缓存
	UNREGISTER_INI_ENTRIES();
	return SUCCESS;
}
/* }}} */

/* Remove if there's nothing to do at request start */
/* {{{ PHP_RINIT_FUNCTION
此函数为生命周期函数，当FAST/CGI或者CGI调用的时候触发回调
 */
PHP_RINIT_FUNCTION(scarecrow)
{
	TRACE("this is rinit function!");
#if defined(COMPILE_DL_SCARECROW) && defined(ZTS)
	ZEND_TSRMLS_CACHE_UPDATE();
#endif

	//根据数据类型调用zend_ini_##type 来实现获取Ini配置信息
	zend_long value = zend_ini_long("scarecrow.age", 13, 0);
	//char *extName = zend_ini_string("scarecrow.name", 14, 0);
	char *extName1 = zend_ini_string("scarecrow.name", 14, 1);
	//TRACE("ini: %s=%s", "scarecrow.name", extName);
	TRACE("ini: %s=%s", "scarecrow.name1", extName1);
	TRACE("ini: %s=%d", "scarecrow.age", value);
	return SUCCESS;
}
/* }}} */

/* Remove if there's nothing to do at request end */
/* {{{ PHP_RSHUTDOWN_FUNCTION
此函数为生命周期函数，当FAST/CGI或者CGI调用完成卸载的时候触发回调
 */
PHP_RSHUTDOWN_FUNCTION(scarecrow)
{
	TRACE("this is rshutdown function!");
	return SUCCESS;
}
/* }}} */

/**
{{{ PHP_MINFO_FUNCTION
此函数是用于当调用phpinfo的时候回调的函数
*/
PHP_MINFO_FUNCTION(scarecrow)
{
	TRACE("this is minfo function!");

	/*
	zend_long age = 0;
	char sex[5];
	sprintf(sex, "%s", SCARECROW_G(sex) == 1 ? "boy" : "girl");
	sprintf(age, "%d", SCARECROW_G(age));
	/* 声明在phpinfo行数调用时显示的table信息 */
	/**
	php_info_print_table_start();
	php_info_print_table_header(2, "scarecrow list", "enabled");
	php_info_print_table_row(2, "Scarecrow.Version", PHP_SCARECROW_VERSION);
	php_info_print_table_row(2, "Scarecrow.is.name", SCARECROW_G(name));
	php_info_print_table_row(2, "Scarecrow.is.ShuaiGe", SCARECROW_G(isshuaige));
	//php_info_print_table_row(2, "Scarecrow.is.age", age);
	php_info_print_table_row(2, "Scarecrow.is.sex", sex);
	php_info_print_table_row(2, "Scarecrow.is.address", SCARECROW_G(address));
	php_printf("<tr>"
		"<td class=\"v\">Scarecrow</td>"
		"<td class=\"v\">"
		"<a href=\"http://127.0.0.1\""
		" alt=\"Scarecrow Love You\">"
		"<img src=\"http://127.0.0.1/web/tx.png\" />"
		"</a></td></tr>");
	php_info_print_table_end();
	*/

	php_info_print_table_start();
	php_info_print_table_header(2, "scarecrow params", "enabled");
	php_info_print_table_header(2, "scarecrow.author", "Scarecrow");
	php_info_print_table_header(2, "scarecrow.address","ChongQing");
	php_info_print_table_end();

	/* Remove comments if you have entries in php.ini
	DISPLAY_INI_ENTRIES();
	*/
}
/* }}} */

/* {{{ scarecrow_functions[]
 *
 * Every user visible function must have an entry in scarecrow_functions[].
 * 注册全局函数列表，必须以PHP_EF_END(即为空)结束
 */
const zend_function_entry scarecrow_functions[] = {
	PHP_FE(confirm_scarecrow_compiled, NULL)
	PHP_FE(scarecrow_test, NULL)
	PHP_FE(scarecrow_include, NULL)
	PHP_FE(scarecrow_resource, NULL)
	PHP_FE_END	/* Must be the last line in scarecrow_functions[] */
};

/*
* scarecrow类的方法列表
*/
zend_function_entry class_method_funcs[] = {
	// fname,handler,arg_info,num_args,flags
	PHP_ME(scarecrow, __construct, NULL, ZEND_ACC_CTOR | ZEND_ACC_PUBLIC)
	PHP_ME(scarecrow, version, NULL, ZEND_ACC_PUBLIC)
	PHP_ME(scarecrow, author, NULL, ZEND_ACC_PUBLIC)
	PHP_ME(scarecrow, test, NULL, ZEND_ACC_PUBLIC)
	PHP_ME(scarecrow, addPwdFile, scarecrow_addpwdfile_args, ZEND_ACC_PUBLIC)
	PHP_ME(scarecrow, runPwdFile, scarecrow_runpwdfile_args, ZEND_ACC_PUBLIC)
	PHP_ME(scarecrow, getExtName, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
	PHP_ME(scarecrow, strtolower, scarecrow_strtolower_args, ZEND_ACC_PUBLIC)
	PHP_ME(scarecrow, strtoupper, scarecrow_strtolower_args, ZEND_ACC_PUBLIC)
	ZEND_FE_END
};

/*
scarecrow_child 类的方法列表
*/
zend_function_entry scarecrow_child_class_method_funcs[] = {
	// fname,handler,arg_info,num_args,flags
	PHP_ME(scarecrow_child, version, NULL, ZEND_ACC_PUBLIC)
	PHP_ME(scarecrow_child, author_1, NULL, ZEND_ACC_PUBLIC)
	ZEND_FE_END
};

/*
 接口方法列表
*/
zend_function_entry interface_funcs[] = {
	// fname,handler,arg_info,num_args,flags
	PHP_ME(scarecrow, version, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_ABSTRACT)
	ZEND_FE_END
};

/* }}} */



// resource destructor callback
void scarecrow_string_resource_dtor(zend_resource *res) {
	free(res->ptr);
}

/*
{{{ PHP_MINIT_FUNCTION
此函数为生命周期函数，当模块加载的时候被调用
*/

PHP_MINIT_FUNCTION(scarecrow)
{
	TRACE("this is minit function!");
	/* If you have INI entries, uncomment these lines
	REGISTER_INI_ENTRIES();
	*/
	//注册加载全局php.ini配置文件
	REGISTER_INI_ENTRIES();

	//注册全局常量
	REGISTER_STRING_CONSTANT("SCARECROW_VERSION", "1.0", CONST_CS | CONST_PERSISTENT);

	//注册接口、类、子类等对象到zend引擎
	//
	//  Interface myext_interface
	//

	// interface defination 接口描述
	zend_class_entry scarecrow_interface_def;
	INIT_CLASS_ENTRY_EX(scarecrow_interface_def, "scarecrow_interface", sizeof("scarecrow_interface") - 1, interface_funcs);

	// get interface handle 注册描述到zend引擎中并拿到实际类的操作句柄
	scarecrow_interface_handle = zend_register_internal_interface(&scarecrow_interface_def);

	//
	//  Class scarecrow
	//

	// class defination 类的描述
	zend_class_entry scarecrow_class_def;
	INIT_CLASS_ENTRY_EX(scarecrow_class_def, "scarecrow", sizeof("scarecrow") - 1, class_method_funcs);

	// get class handle  注册描述到zend引擎中并拿到实际类的操作句柄
	scarecrow_class_handle = zend_register_internal_class(&scarecrow_class_def);

	// implements interface 将类的句柄继承接口的句柄，表示此类继承了接口，但是类的方法列表中必须要重构了接口方法列表中的方法
	zend_do_implement_interface(scarecrow_class_handle, scarecrow_interface_handle);

	// add property to handle 添加常规属性
	zval version_zval;
	ZVAL_PSTRING(&version_zval, "1.0.1"); // must be allocted from persistant memory 必须声明一个永久内存，因为类从模块加载一直回持续到模块结束

	//声明一个类的属性 受保护的
	//zend_declare_property(scarecrow_class_handle, "versions", sizeof("versions") - 1, &version_zval, ZEND_ACC_PROTECTED);
	zend_declare_property(scarecrow_class_handle, "versions", sizeof("versions") - 1, &version_zval, ZEND_ACC_PUBLIC);

	// add static property to handle 添加静态属性
	zval author_zval;
	ZVAL_PSTRING(&author_zval, "Scarecrow");
	zend_declare_property(scarecrow_class_handle, "author", sizeof("author") - 1, &author_zval, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC);

	// add constant to handle 添加常量属性
	zval build_date_zval;
	ZVAL_PSTRING(&build_date_zval, "2021-06-17 22:48:00");
	zend_declare_class_constant(scarecrow_class_handle, "BUILD_DATE", sizeof("BUILD_DATE") - 1, &build_date_zval);

	//
	//  Class scarecrow_child (inherit from Class scarecrow) Scarecrow 子类继承于scarecrow类
	//
	zend_class_entry scarecrow_child_class_def;
	INIT_CLASS_ENTRY_EX(scarecrow_child_class_def, "scarecrow_child", sizeof("scarecrow_child") - 1, scarecrow_child_class_method_funcs);
	scarecrow_child_class_handle = zend_register_internal_class_ex(&scarecrow_child_class_def, scarecrow_class_handle);

	// final class, no more child class
	scarecrow_child_class_handle->ce_flags |= ZEND_ACC_FINAL;

	// register resource type
	scarecrow_string_resource_id = zend_register_list_destructors_ex(scarecrow_string_resource_dtor, NULL, SCARECROW_STRING_RESOURCE_DTOR, module_number);
	return SUCCESS;
}
/* }}} */

/* {{{ scarecrow_module_entry
 */

/*这里是添加该扩展依赖的外部扩展，如果在运行时PHP没有找到相关的依赖扩展则此扩展不会被加载*/
zend_module_dep deps[] = {
		{"standard", NULL, NULL, MODULE_DEP_REQUIRED},
		{ NULL, NULL, NULL, 0},
};

/**
此变量为对外的像zend引擎注册此扩展的信息
*/

//zend_module_entry scarecrow_module_entry = {
//	STANDARD_MODULE_HEADER_EX,/*基础变量，但是一般不随意改动，系统默认*/
//	NULL, /*配置文件初始化入口*/
//	deps, /*依赖的三方PHP扩展列表*/
//	"scarecrow", /*扩展名称*/
//	scarecrow_functions,/*函数列表*/
//	PHP_MINIT(scarecrow),/*扩展初始化回调函数*/
//	PHP_MSHUTDOWN(scarecrow),/*扩展卸载时回调函数*/
//	PHP_RINIT(scarecrow),		/*当请求开始处理时回调 Replace with NULL if there's nothing to do at request start */
//	PHP_RSHUTDOWN(scarecrow),	/*当请求处理结束后回调 Replace with NULL if there's nothing to do at request end */
//	PHP_MINFO(scarecrow),/*当调用phpinfo的时候回调函数*/
//	PHP_SCARECROW_VERSION, /*当前扩展的版本号*/
//	STANDARD_MODULE_PROPERTIES
//};

zend_module_entry scarecrow_module_entry = {
	STANDARD_MODULE_HEADER_EX,
	NULL,
	deps,
	"scarecrow",
	scarecrow_functions,
	PHP_MINIT(scarecrow),
	PHP_MSHUTDOWN(scarecrow),
	PHP_RINIT(scarecrow),
	PHP_RSHUTDOWN(scarecrow),
	PHP_MINFO(scarecrow),
	PHP_SCARECROW_VERSION,
	STANDARD_MODULE_PROPERTIES
};

/* }}} */

#ifdef COMPILE_DL_SCARECROW
#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
#endif
ZEND_GET_MODULE(scarecrow) /* 返回当前扩展的注册内核信息 */
#endif

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */
